#!/usr/bin/env python3
"""
磁盘存储系统测试 - 专门针对实训第2部分要求

测试内容：
1. 页式存储系统（页分配/释放/读写）
2. 缓存机制（LRU/FIFO/Clock替换策略）
3. 存储访问接口
4. 数据表与页映射关系
5. 持久化机制
"""
import os
import sys
import tempfile
import shutil
import time

# 路径设置
current_dir = os.path.dirname(os.path.abspath(__file__))
parent_dir = os.path.dirname(current_dir)
sys.path.insert(0, parent_dir)

def test_page_storage_system():
    """测试页式存储系统"""
    print("1️⃣ 测试页式存储系统...")
    
    try:
        from page_manager import PageManager
        from constants import PAGE_SIZE
        
        # 创建临时数据库
        temp_dir = tempfile.mkdtemp()
        db_path = os.path.join(temp_dir, "page_test_db")
        
        page_manager = PageManager(db_path)
        
        # 测试页分配
        page_id1 = page_manager.allocate_page()
        page_id2 = page_manager.allocate_page()
        page_id3 = page_manager.allocate_page()
        
        print(f"   分配页面: {page_id1}, {page_id2}, {page_id3}")
        
        # 测试页写入
        test_data1 = b"Hello Page 1" + b"\x00" * (PAGE_SIZE - 12)
        test_data2 = b"Hello Page 2" + b"\x00" * (PAGE_SIZE - 12)
        
        page_manager.write_page(page_id1, test_data1)
        page_manager.write_page(page_id2, test_data2)
        
        # 测试页读取
        read_data1 = page_manager.read_page(page_id1)
        read_data2 = page_manager.read_page(page_id2)
        
        if read_data1 != test_data1 or read_data2 != test_data2:
            raise Exception("页读写数据不一致")
        
        # 测试页释放
        page_manager.deallocate_page(page_id3)
        
        # 再次分配应该重用释放的页面
        page_id4 = page_manager.allocate_page()
        
        page_manager.close()
        shutil.rmtree(temp_dir)
        
        print("   ✅ 页式存储系统测试通过")
        return True
        
    except Exception as e:
        print(f"   ❌ 页式存储系统测试失败: {e}")
        return False

def test_cache_mechanisms():
    """测试缓存机制"""
    print("2️⃣ 测试缓存机制...")
    
    try:
        from storage_engine import StorageEngine, CachePolicy
        
        # 测试不同缓存策略
        policies = [CachePolicy.LRU, CachePolicy.FIFO, CachePolicy.CLOCK]
        
        for policy in policies:
            print(f"   测试{policy.value}缓存策略...")
            
            temp_dir = tempfile.mkdtemp()
            db_path = os.path.join(temp_dir, f"cache_test_{policy.value}")
            
            engine = StorageEngine(
                db_path=db_path,
                cache_size=5,  # 小缓存便于测试
                cache_policy=policy,
                enable_locking=False
            )
            
            # 分配页面并写入数据
            page_ids = []
            for i in range(8):  # 超过缓存大小
                page_id = engine.page_manager.allocate_page()
                page_ids.append(page_id)
                test_data = f"Cache test {i}".encode() + b"\x00" * 4000
                engine.page_manager.write_page(page_id, test_data)
            
            # 读取页面，触发缓存
            for page_id in page_ids:
                data = engine.cache_manager.get_page(page_id)
                if len(data) != 4096:
                    raise Exception(f"缓存读取数据长度错误: {len(data)}")
            
            # 检查缓存统计
            stats = engine.get_cache_stats()
            replacements = getattr(stats, 'replacements', getattr(stats, 'replacement_count', 0))
            print(f"     {policy.value}: 请求={stats.total_requests}, 命中={stats.cache_hits}, 替换={replacements}")
            
            if stats.total_requests == 0:
                raise Exception("缓存统计异常")
            
            engine.close()
            shutil.rmtree(temp_dir)
        
        print("   ✅ 缓存机制测试通过")
        return True
        
    except Exception as e:
        print(f"   ❌ 缓存机制测试失败: {e}")
        return False

def test_storage_interfaces():
    """测试存储访问接口"""
    print("3️⃣ 测试存储访问接口...")
    
    try:
        from storage_engine import StorageEngine, CachePolicy
        from table_schema import Column, ColumnType
        
        temp_dir = tempfile.mkdtemp()
        db_path = os.path.join(temp_dir, "interface_test_db")
        
        engine = StorageEngine(db_path=db_path, cache_size=20, enable_locking=False)
        
        # 测试表创建
        columns = [
            Column("id", ColumnType.INT, primary_key=True),
            Column("name", ColumnType.VARCHAR, length=50),
            Column("score", ColumnType.FLOAT)
        ]
        
        result = engine.create_table("students", columns)
        if not result:
            raise Exception("创建表失败")
        
        # 测试数据插入
        test_records = [
            {"id": 1, "name": "张三", "score": 95.5},
            {"id": 2, "name": "李四", "score": 87.0},
            {"id": 3, "name": "王五", "score": 92.5}
        ]
        
        for record in test_records:
            result = engine.insert_record("students", record)
            if not result:
                raise Exception(f"插入记录失败: {record}")
        
        # 测试数据查询
        all_records = engine.select_records("students")
        if len(all_records) != 3:
            raise Exception(f"查询记录数量错误: 期望3，实际{len(all_records)}")
        
        # 测试条件查询
        high_score = engine.select_records("students", {"score": {"$gt": 90}})
        if len(high_score) != 2:
            raise Exception(f"条件查询错误: 期望2条高分记录，实际{len(high_score)}条")
        
        print(f"   数据统计: 总记录={len(all_records)}, 高分记录={len(high_score)}")
        
        engine.close()
        shutil.rmtree(temp_dir)
        
        print("   ✅ 存储访问接口测试通过")
        return True
        
    except Exception as e:
        print(f"   ❌ 存储访问接口测试失败: {e}")
        return False

def test_table_page_mapping():
    """测试数据表与页映射关系"""
    print("4️⃣ 测试数据表与页映射关系...")
    
    try:
        from storage_engine import StorageEngine
        from table_schema import Column, ColumnType
        
        temp_dir = tempfile.mkdtemp()
        db_path = os.path.join(temp_dir, "mapping_test_db")
        
        engine = StorageEngine(db_path=db_path, cache_size=30, enable_locking=False)
        
        # 创建多个表
        tables = ["table1", "table2", "table3"]
        columns = [Column("id", ColumnType.INT), Column("data", ColumnType.VARCHAR, length=100)]
        
        for table_name in tables:
            engine.create_table(table_name, columns)
        
        # 向每个表插入数据
        for i, table_name in enumerate(tables):
            for j in range(10):  # 每表10条记录
                record = {"id": j, "data": f"{table_name}_data_{j}"}
                engine.insert_record(table_name, record)
        
        # 验证表映射
        for table_name in tables:
            schema = engine.get_table_schema(table_name)
            if not schema:
                raise Exception(f"无法获取表{table_name}的schema")
            
            if len(schema.page_ids) == 0:
                raise Exception(f"表{table_name}没有分配页面")
            
            print(f"   {table_name}: {len(schema.page_ids)}个页面")
        
        # 验证数据隔离
        for table_name in tables:
            records = engine.select_records(table_name)
            if len(records) != 10:
                raise Exception(f"表{table_name}记录数量错误: {len(records)}")
            
            # 验证数据只属于当前表
            for record in records:
                if not record["data"].startswith(table_name):
                    raise Exception(f"表{table_name}包含其他表的数据: {record}")
        
        engine.close()
        shutil.rmtree(temp_dir)
        
        print("   ✅ 数据表与页映射测试通过")
        return True
        
    except Exception as e:
        print(f"   ❌ 数据表与页映射测试失败: {e}")
        return False

def test_data_persistence():
    """测试数据持久化"""
    print("5️⃣ 测试数据持久化...")
    
    try:
        from storage_engine import StorageEngine
        from table_schema import Column, ColumnType
        
        temp_dir = tempfile.mkdtemp()
        db_path = os.path.join(temp_dir, "persist_test_db")
        
        # 第一阶段：创建数据
        engine1 = StorageEngine(db_path=db_path, cache_size=20, enable_locking=False)
        
        columns = [
            Column("id", ColumnType.INT, primary_key=True),
            Column("name", ColumnType.VARCHAR, length=50),
            Column("value", ColumnType.FLOAT)
        ]
        
        engine1.create_table("persist_test", columns)
        
        # 插入测试数据
        test_data = [
            {"id": 1, "name": "数据1", "value": 123.45},
            {"id": 2, "name": "数据2", "value": 678.90},
            {"id": 3, "name": "数据3", "value": 234.56}
        ]
        
        for record in test_data:
            engine1.insert_record("persist_test", record)
        
        engine1.close()  # 关闭第一个引擎
        
        # 第二阶段：重新打开验证数据
        engine2 = StorageEngine(db_path=db_path, cache_size=20, enable_locking=False)
        
        # 验证表存在
        if not engine2.table_exists("persist_test"):
            raise Exception("重启后表不存在")
        
        # 验证数据存在
        recovered_records = engine2.select_records("persist_test")
        if len(recovered_records) != len(test_data):
            raise Exception(f"数据恢复数量错误: 期望{len(test_data)}, 实际{len(recovered_records)}")
        
        # 验证数据内容 - 按ID排序比较
        recovered_records_sorted = sorted(recovered_records, key=lambda x: x["id"])
        test_data_sorted = sorted(test_data, key=lambda x: x["id"])
        
        for i, record in enumerate(recovered_records_sorted):
            original = test_data_sorted[i]
            if (record["id"] != original["id"] or 
                record["name"] != original["name"] or 
                abs(record["value"] - original["value"]) > 0.01):
                raise Exception(f"数据内容错误: {record} vs {original}")
        
        print(f"   恢复数据: {len(recovered_records)}条记录")
        
        engine2.close()
        shutil.rmtree(temp_dir)
        
        print("   ✅ 数据持久化测试通过")
        return True
        
    except Exception as e:
        print(f"   ❌ 数据持久化测试失败: {e}")
        return False

def test_performance_statistics():
    """测试性能统计"""
    print("6️⃣ 测试性能统计...")
    
    try:
        from storage_engine import StorageEngine
        from table_schema import Column, ColumnType
        
        temp_dir = tempfile.mkdtemp()
        db_path = os.path.join(temp_dir, "stats_test_db")
        
        engine = StorageEngine(db_path=db_path, cache_size=10, enable_locking=False)
        
        columns = [Column("id", ColumnType.INT), Column("data", ColumnType.VARCHAR, length=50)]
        engine.create_table("stats_test", columns)
        
        # 执行一些操作
        start_time = time.time()
        
        for i in range(50):
            record = {"id": i, "data": f"统计测试数据{i}"}
            engine.insert_record("stats_test", record)
        
        # 执行查询操作
        for i in range(20):
            engine.select_records("stats_test", {"id": i})
        
        end_time = time.time()
        
        # 获取统计信息
        storage_stats = engine.get_storage_stats()
        cache_stats = engine.get_cache_stats()
        
        print(f"   操作耗时: {end_time - start_time:.3f}秒")
        print(f"   存储统计: 分配页面={getattr(storage_stats, 'pages_allocated', 'N/A')}")
        print(f"   缓存统计: 请求={cache_stats.total_requests}, 命中={cache_stats.cache_hits}")
        
        if cache_stats.total_requests == 0:
            raise Exception("缓存统计异常")
        
        cache_hit_rate = cache_stats.cache_hits / cache_stats.total_requests
        print(f"   缓存命中率: {cache_hit_rate:.2%}")
        
        engine.close()
        shutil.rmtree(temp_dir)
        
        print("   ✅ 性能统计测试通过")
        return True
        
    except Exception as e:
        print(f"   ❌ 性能统计测试失败: {e}")
        return False

def main():
    """主测试函数"""
    print("🗄️  磁盘存储系统测试")
    print("=" * 50)
    print("针对实训第2部分：磁盘存储系统设计")
    print("=" * 50)
    
    tests = [
        test_page_storage_system,
        test_cache_mechanisms,
        test_storage_interfaces,
        test_table_page_mapping,
        test_data_persistence,
        test_performance_statistics
    ]
    
    passed = 0
    total = len(tests)
    
    for test_func in tests:
        if test_func():
            passed += 1
        print()
    
    print("=" * 50)
    print(f"🎯 测试结果: {passed}/{total} 通过")
    
    if passed == total:
        print("🎉 磁盘存储系统测试全部通过！")
        print("✅ 页式存储系统正常")
        print("✅ 缓存机制工作正常") 
        print("✅ 存储接口功能完整")
        print("✅ 数据持久化可靠")
        print("\n💡 你的磁盘存储系统已经完成实训要求！")
    else:
        print(f"⚠️  有 {total - passed} 个测试失败")
        print("请检查对应的功能模块")
    
    print("=" * 50)

if __name__ == "__main__":
    main()
